//
// Created by 余代宸 -Yu DaiChen on 2021/12/18
// QQ-E-MAIL:250074249@qq.com
//

#pragma once
#ifndef MINI_REDIS_C_MALLOC_H
#define MINI_REDIS_C_MALLOC_H

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#ifdef __unix__
#include <pthread.h>
#include <unistd.h>
#endif // __unix__
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
#define PREFIX_SIZE (sizeof(long long))
#else
#define PREFIX_SIZE (sizeof(size_t))
#endif

#if defined(USE_JEMALLOC)
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
#include <jemalloc/jemalloc.h>
#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
#define HAVE_MALLOC_SIZE 1
#define cmallocSize(p) je_malloc_usable_size(p)
#else
#error "Newer version of jemalloc required"
#endif

#elif defined(__APPLE__)
#include <malloc/malloc.h>
#define HAVE_MALLOC_SIZE 1
#define cmallocSize(p) malloc_size(p)
#endif

#ifndef C_MALLOC_LIB
#define C_MALLOC_LIB "libc"
#endif

/**
 * @brief 指定内存溢出的回调函数
 * @param (*oomHandler)(size_t) [in]: 函数指针 oomHandler
 */
void setOutOfMemoryHandler(void (*oomHandler)(size_t));


/**
 * @brief 分配size个字节的内存
 * @param size 待分配内存大小
 * @return 分配的堆内存的地址
 */
void *cMalloc(size_t size);

/**
 * @brief 重新分配size个字节的内存，并且初始化该堆内存
 * @param size[in]:	待分配内存大小
 * @return 分配的堆内存的地址
 */
void *cMallocWithZero(size_t size);

/**
 * @brief Realloc()要完成的功能是给首地址ptr的内存空间，重新分配大小
 * 如果失败了，则在其它位置新建一块大小为size字节的空间，将原先的数据复制到新的内存空间
 * 并返回这段内存首地址【原内存会被系统自然释放】。cReMalloc()要完成的功能也类似。
 * @param *ptr [in]: 源空间的大小
 * @param size [in]: 待分配内存大小
 * @return 分配的堆内存的地址
 */
void *cReMalloc(void *ptr, size_t size);

/**
 * @brief 销毁内存空间
 * @param *ptr [in]: 源空间的大小
 * @return 分配堆内存的地址
 */
void cFree(void *ptr);

/**
 * @brief 拷贝一份char* s内存空间
 * @param str [int]
 * @return 拷贝str后，得到的新字符串的首地址
 */
char *strDup(const char *str);

/**
 * @brief 开启线程安全
 */
void enableThreadSafeness(void);

/**
 * @brief 获取已近使用的内存
 * @return
 */
size_t getUsedMemory();


/**
 * @brief 获取内存碎片率  RSS与所分配总内存空间的比值
 * @param rss [in]: 使用getMemoryRss()获取碎片
 * @return float 碎片率
 */
float getFragmentationRatio(size_t rss);

/**
 * @brief  获取RSS ,它是是常驻内存集（Resident Set Size）
 * 			RSS 不包括进入交换分区的内存表示该进程分配的内存大小
 * 			RSS 包括共享库占用的内存（只要共享库在内存中）
 * 			RSS 包括所有分配的栈内存和堆内存
 * 			RSS 中有一部分来自共享库，而共享库可能被许多进程使用
 * 			所以如果把所有进程的 RSS 加起来，可能比系统内存还要大
 * @return size_t个字节内存
 */
size_t getMemoryRss(void);

/**
 * @brief 获取私有的被占有的脏内存
 * 完成的操作就是扫描 /proc/self/smaps文件，统计其中所有 Private_Dirty字段的和
 * Rss=Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty
 *
 * Shared_Clean:多进程共享的内存，且其内容未被任意进程修改
 * Shared_Dirty:多进程共享的内存，但其内容被某个进程修改
 * Private_Clean:某个进程独享的内存，且其内容没有修改
 * Private_Dirty:某个进程独享的内存，但其内容被该进程修改
 */
size_t getPrivateDirty(void);


#endif //MINI_REDIS_C_MALLOC_H
